import { Camera, PerspectiveCamera, Scene, Vector3, WebGLRenderer } from 'three'
import { OrbitControls } from 'three/examples/jsm/Addons.js'
import type { ThreeSceneController } from './ThreeSceneController'

/**
 * 控制three3D场景的画布
 */
export class ThreeRender3DController {

  private _sceneController: ThreeSceneController | null = null

  private _camera: Camera

  private _controls: OrbitControls | null = null
  private _renderer: WebGLRenderer | null = null
  private _canvasDomContainer: HTMLDivElement | null = null
  private _canvasWidth: number = 0
  private _canvasHeight: number = 0

  public get camera(): Camera {
    return this._camera
  }

  public get scene(): Scene | null {
    if (this._sceneController) {
      return this._sceneController.scene
    }
    return null
  }

  public get controls(): OrbitControls | null {
    return this._controls
  }

  public get renderer(): WebGLRenderer | null {
    return this._renderer
  }

  constructor() {
    this._camera = new Camera()
  }

  public init(sceneController: ThreeSceneController, canvasContainer: HTMLDivElement) {
    this._sceneController = sceneController
    this._canvasDomContainer = canvasContainer
    this._canvasWidth = canvasContainer.offsetWidth
    this._canvasHeight = canvasContainer.offsetHeight


    // 这里获取offsetWidth必须该dom是可见的，也就是加入到dom树中的
    // const width = container.offsetWidth;
    // const height = container.offsetHeight;
    this.initRenderer()

    this.initCamera()

    // 创建轨道控制器，需要绑定： (控制的相机, 事件监听的html元素)
    if (this._camera && this._renderer) {
      // 绑定轨道控制器后，控制器将接管相机的lookAt, 替代的可以直接用控制器.target来实现相机的lookAt功能
      this._controls = new OrbitControls(this._camera, this._renderer.domElement)
      this._controls.target = new Vector3(0, 0, 0)
    }

    this.mountRendererDomToContainer();
  }

  public startRender() {

    try {
      const mainScene: Scene = this.scene as Scene;
      const bottomScene: Scene = this._sceneController?.bottomScene as Scene;
      const camera: Camera = this._camera as Camera;
      const controls: OrbitControls = this._controls as OrbitControls;
      const renderer: WebGLRenderer = this._renderer as WebGLRenderer;

      render()
      function render() {
        controls.update()
        renderer.render(bottomScene, camera);
        renderer.autoClear = false;
        renderer.render(mainScene, camera)
        renderer.autoClear = true;
        // requestAnimationFrame，由于是异步调用，调用的时机可能不均匀
        // 渲染下一帧的时候会调用render函数
        requestAnimationFrame(render)
      }
    } catch (error) {
      console.error(error)
    }

  }

  private mountRendererDomToContainer() {
    if (!this._renderer) {
      return
    };
    this._canvasDomContainer?.appendChild(this._renderer.domElement)
  }

  private initCamera() {
    // 创建相机
    const camera = new PerspectiveCamera(45, this._canvasWidth / this._canvasHeight, 0.1, 100000000)

    // (x,y,z)
    camera.position.set(0, 800, 2500) // 投影相机设置这个可以实现类似的缩放

    camera.zoom = 1 // 投影相机设置缩放倍速没用

    // 将相机添加到场景(不需要)
    // scene.add(camera);
    this._camera = camera
  }

  private initRenderer() {
    // 初始化渲染器 antialias: true -- 抗锯齿，解决锯齿严重问题
    const renderer = new WebGLRenderer({ antialias: true, alpha: true })
    renderer.setPixelRatio(window.devicePixelRatio)
    renderer.setSize(this._canvasWidth, this._canvasHeight) // 设置渲染尺寸大小
    renderer.setPixelRatio(window.devicePixelRatio);
    this._renderer = renderer
  }

  public getRendererInfo() {
    if (this._renderer) {
      console.log(this._renderer.info)
    }
  }

  public getRendererDom(): HTMLCanvasElement | null {
    if (!this._renderer) {
      return null
    }
    return this._renderer.domElement
  }
}
